/**
 * 
 */
package de.uni_leipzig.informatik.asv.unsupervised_pos_tagger.datacreation;
import it.unimi.dsi.fastutil.objects.Object2IntAVLTreeMap;
import it.unimi.dsi.fastutil.objects.Object2IntMap.Entry;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
/**
 * 
 * @author Christoph Teichmann
 * created Jun 4, 2014 1:54:33 PM
 * @version 0.1
 */
public class CreateGraph
{
	/**
	 * @param leftToRight
	 * @param rightToLeft
	 * @param l1fts
	 */
	public CreateGraph(boolean leftToRight, boolean rightToLeft,
			FeatureType[] l1fts)
	{
		this.leftToRight = leftToRight;
		this.rightToLeft = rightToLeft;
		this.l1fts = l1fts;
	}
	/**
	 * 
	 */
	private final boolean leftToRight;
	/**
	 * 
	 */
	private final boolean rightToLeft;
	/**
	 * 
	 */
	private final FeatureType[] l1fts;
	/**
	 * 
	 */
	private final Object2IntAVLTreeMap<Edge> m = new Object2IntAVLTreeMap<>();
	/**
	 * 
	 *
	 * @throws IOException
	 */
	public void addAlignments(BufferedReader br) throws IOException
	{
		String line = br.readLine();
		String[] parts = line.split("\\t+");
		String lang1 = parts[0].trim();
		String lang2 = parts[1].trim();
		String last1Word = null;
		String last2Word = null;
		while((line = br.readLine()) != null)
		{
			if(line.matches("\\s*"))
			{
				last1Word = null;
				last2Word = null;
				continue;
			}
			parts = line.split("\\t+");
			last1Word = nextStep(lang1, last1Word, parts[0].trim());
			last2Word = nextStep(lang2, last2Word, parts[1].trim());
			if(this.leftToRight)
			{addCrossLanguage(last1Word,last2Word);}
			if(this.rightToLeft)
			{addCrossLanguage(last2Word,last1Word);}
		}
	}
	
	public void addFreeAlignments(BufferedReader br) throws IOException
	{
		String firstLanguage;
		String secondLanguage;
		ArrayList<String> firstSentence = new ArrayList<>();
		ArrayList<String> secondSentence = new ArrayList<>();
		String line;
		while((line = br.readLine()) != null)
		{
			firstSentence.clear();
			secondSentence.clear();
			firstLanguage = line.trim();
			addLines(br, firstLanguage, firstSentence);
			if((line = br.readLine()) == null)
			{break;}
			secondLanguage = line.trim();
			addLines(br,secondLanguage,secondSentence);
			while((line = br.readLine()) != null)
			{
				if(line.matches("\\s*"))
				{break;}
				String[] parts = line.trim().split("\\s+");
				int one = Integer.parseInt(parts[0]);
				int two = Integer.parseInt(parts[1]);
				if(this.leftToRight)
				{this.addCrossLanguage(firstSentence.get(one), secondSentence.get(two));}
				if(this.rightToLeft)
				{this.addCrossLanguage(secondSentence.get(two), firstSentence.get(one));}
			}
		}
	}
	/**
	 * 
	 * @param br
	 * @param firstLanguage
	 * @param firstSentence
	 * @throws IOException
	 */
	private void addLines(BufferedReader br, String firstLanguage,
			ArrayList<String> firstSentence) throws IOException
	{
		String line;
		while((line = br.readLine()) != null)
		{
			if(line.matches("\\s*"))
			{break;}
			firstSentence.add(this.makeWord(firstLanguage, line.trim()));
			if(firstSentence.size() > 1)
			{this.addFollowing(firstSentence.get(firstSentence.size()-2),
					firstSentence.get(firstSentence.size()-1));}
		}
	}
	/**
	 *
	 * @param lang1
	 * @param last1Word
	 * @param s
	 * @return
	 */
	private String nextStep(String lang1, String last1Word, String s)
	{
		if(!s.equals(""))
		{
			s = makeWord(lang1, s);
			if(last1Word != null)
			{this.addFollowing(last1Word, s);}
			last1Word = s;
		}
		return last1Word;
	}
	/**
	 * 
	 * @param lang1
	 * @param s
	 * @return
	 */
	private String makeWord(String lang1, String s)
	{
		return reduce(s,this.l1fts) + MARKER + lang1;
	}
	/**
	 *
	 * @param string
	 * @param l1fts2
	 * @return
	 */
	private String reduce(String string, FeatureType[] feats)
	{
		for(FeatureType ft : feats)
		{string = ft.process(string);}
		return string;
	}
	/**
	 * 
	 *
	 * @param br
	 * @throws IOException
	 */
	public void addSequentialOnly(BufferedReader br) throws IOException
	{
		String line = br.readLine().trim();
		String language = line;
		String lastWord = null;
		while((line = br.readLine()) != null)
		{
			if(line.matches("\\s*"))
			{
				lastWord = null;
				continue;
			}
			String nextWord = new String(makeWord(language, line));
			if(lastWord != null)
			{this.addFollowing(lastWord, nextWord);}
			lastWord = nextWord;
		}
	}
	/**
	 * 
	 */
	private final static String MARKER = "|";
	/**
	 *
	 * @param lastWord
	 * @param translation
	 */
	private void addCrossLanguage(String lastWord, String translation)
	{
		Edge eg = new Edge(lastWord, translation, CROSSLABEL);
		this.m.put(eg, this.m.getInt(eg)+1);
	}
	/**
	 * 
	 */
	private final static String CROSSLABEL = "TRANSLATE";
	/**
	 *
	 * @param lastWord
	 * @param string
	 * @param eg
	 * @return
	 */
	private void addFollowing(String lastWord, String follower)
	{
		Edge eg = new Edge(lastWord, follower, FOLLOWING);
		this.m.put(eg, this.m.getInt(eg)+1);
	}
	/**
	 * 
	 */
	private final static String FOLLOWING = "FOLLOWING";
	/**
	 * 
	 *
	 * @param bw
	 * @throws IOException
	 */
	public void writeOutEdges(BufferedWriter bw) throws IOException
	{
		boolean first = true;
		Iterator<Entry<Edge>> it = this.m.object2IntEntrySet().iterator();
		while(it.hasNext())
		{
			if(first)
			{first = false;}
			else
			{bw.newLine();}
			Entry<Edge> e = it.next();
			Edge eg = e.getKey();
			int amount = e.getIntValue();
			bw.write(eg.from);
			bw.write("\t");
			bw.write(eg.to);
			bw.write("\t");
			bw.write(eg.label);
			bw.write("\t");
			bw.write(Integer.toString(amount));
		}
	}
	/**
	 * 
	 * @author Christoph Teichmann
	 * created Jun 4, 2014 2:01:47 PM
	 * @version 0.1
	 */
	private class Edge implements Comparable<Edge>
	{
		/**
		 * 
		 * @param from
		 * @param to
		 * @param label
		 */
		public Edge(String from, String to, String label)
		{
			this.from = from;
			this.to = to;
			this.label = label;
		}
		/* (non-Javadoc)
		 * @see java.lang.Object#toString()
		 */
		@Override
		public String toString()
		{
			StringBuilder builder = new StringBuilder();
			builder.append("Edge [from=");
			builder.append(from);
			builder.append(", to=");
			builder.append(to);
			builder.append(", label=");
			builder.append(label);
			builder.append("]");
			return builder.toString();
		}
		/**
		 * 
		 */
		private String from;
		/**
		 * 
		 */
		private String to;
		/**
		 * 
		 */
		private String label;
		/* (non-Javadoc)
		 * @see java.lang.Comparable#compareTo(java.lang.Object)
		 */
		@Override
		public int compareTo(Edge o)
		{
			int num = this.from.compareTo(o.from);
			if(num == 0)
			{
				num = this.to.compareTo(o.to);
				if(num == 0)
				{
					num = this.label.compareTo(o.label);
					return num;
				}
				else
				{return num;}
			}
			else
			{return num;}
		}
		/* (non-Javadoc)
		 * @see java.lang.Object#equals(java.lang.Object)
		 */
		@Override
		public boolean equals(Object obj)
		{
			if(!(obj instanceof Edge))
			{return false;}
			else
			{return this.compareTo((Edge) obj) == 0;}
		}
	}
}